package ${groupId}.shiro;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.session.mgt.SessionValidationScheduler;
import org.apache.shiro.session.mgt.eis.*;
import org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import ${groupId}.shiro.cm.RetryLimitHashedCredentialsMatcher;
import ${groupId}.shiro.filter.CustomDefaultFilterChainManager;
import ${groupId}.shiro.filter.CustomPathMatchingFilterChainResolver;
import ${groupId}.shiro.filter.SysUserFilter;
import ${groupId}.shiro.realm.UserRealm;

@Configuration
public class ShiroConf {

	@Bean public EhCacheManager ehCacheManager(){
		EhCacheManager ehCacheManager = new EhCacheManager();
		ehCacheManager.setCacheManagerConfigFile("classpath:ehcache/ehcache.xml");
		return ehCacheManager;
	}
	
	@Bean public CredentialsMatcher credentialsMatcher(){
		RetryLimitHashedCredentialsMatcher cm = new RetryLimitHashedCredentialsMatcher(ehCacheManager());
		cm.setHashAlgorithmName("md5");
		cm.setHashIterations(2);
		cm.setStoredCredentialsHexEncoded(true);
		return cm;
	}
	
	@Bean public UserRealm userRealm(){
		UserRealm realm = new UserRealm();
		realm.setCredentialsMatcher(credentialsMatcher());
		realm.setCachingEnabled(false);
		return realm;
	}
	
	@Bean
	public SessionIdGenerator sessionIdGenerator(){
		return new JavaUuidSessionIdGenerator();
	}
	
	@Bean
	public SessionDAO sessionDAO(){
		EnterpriseCacheSessionDAO enterpriseCacheSessionDAO = new EnterpriseCacheSessionDAO();
		enterpriseCacheSessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
		enterpriseCacheSessionDAO.setSessionIdGenerator(sessionIdGenerator());
		return enterpriseCacheSessionDAO;
	}
	
	@Bean
	public SimpleCookie sessionIdCookie(){
		SimpleCookie simpleCookie = new SimpleCookie("sid");
		simpleCookie.setHttpOnly(true);
		simpleCookie.setMaxAge(180000);
		return simpleCookie;
	}

	@Bean
	public SimpleCookie rememberMeCookie(){
		SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
		simpleCookie.setHttpOnly(true);
		simpleCookie.setMaxAge(180000);
		return simpleCookie;
	}
	
	@Bean
	public RememberMeManager rememberMeManager(){
		CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
		cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
		cookieRememberMeManager.setCookie(rememberMeCookie());
		return cookieRememberMeManager;
	}
	
	@Bean
	public DefaultWebSessionManager sessionManager(){
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setGlobalSessionTimeout(1800000);
		sessionManager.setDeleteInvalidSessions(true);
		sessionManager.setSessionValidationSchedulerEnabled(true);
		sessionManager.setSessionDAO(sessionDAO());
		sessionManager.setSessionIdCookie(sessionIdCookie());
		sessionManager.setSessionIdCookieEnabled(true);
		return sessionManager;
	}
	@Bean
	public SessionValidationScheduler sessionValidationScheduler(){
		QuartzSessionValidationScheduler sessionValidationScheduler = new QuartzSessionValidationScheduler();
		sessionValidationScheduler.setSessionValidationInterval(1800000);
		sessionValidationScheduler.setSessionManager(sessionManager());
		return sessionValidationScheduler;
	}
	
	@Bean
	public DefaultWebSecurityManager securityManager(){
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(userRealm());
		securityManager.setSessionManager(sessionManager());
		securityManager.setCacheManager(ehCacheManager());
		securityManager.setRememberMeManager(rememberMeManager());
		SecurityUtils.setSecurityManager(securityManager);
		return securityManager;
	}
	
	
	@Bean
	public FormAuthenticationFilter formAuthenticationFilter(){
		FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();
		formAuthenticationFilter.setUsernameParam("username");
		formAuthenticationFilter.setPasswordParam("password");
		formAuthenticationFilter.setRememberMeParam("rememberMe");
		formAuthenticationFilter.setLoginUrl("/dologin");
		return formAuthenticationFilter;
	}
	
	@Bean
	public SysUserFilter sysUserFilter(){
		return new SysUserFilter();
	}
	
	@Bean
	public CustomDefaultFilterChainManager customDefaultFilterChainManager(){
		CustomDefaultFilterChainManager cdfcm = new CustomDefaultFilterChainManager();
		cdfcm.setLoginUrl("/login");
		cdfcm.setSuccessUrl("/index");
		cdfcm.setUnauthorizedUrl("/unauthorized");
		
		Map<String, Filter> customFilters = new LinkedHashMap<>();
		customFilters.put("authc", formAuthenticationFilter());
		customFilters.put("sysUser", sysUserFilter());
		cdfcm.setCustomFilters(customFilters);
		
		Map<String, String> filterChainDefinitionMap = new HashMap<>();
		filterChainDefinitionMap.put("/login", "authc");
		filterChainDefinitionMap.put("/", "anon");
		filterChainDefinitionMap.put("/logout", "logout");
		filterChainDefinitionMap.put("/unauthorized", "authc");
		filterChainDefinitionMap.put("/login", "authc");
		filterChainDefinitionMap.put("/**", "user,sysUser");
		cdfcm.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return cdfcm;
	}
	
	
	@Bean
	public CustomPathMatchingFilterChainResolver customPathMatchingFilterChainResolver(){
		CustomPathMatchingFilterChainResolver c = new CustomPathMatchingFilterChainResolver();
		c.setCustomDefaultFilterChainManager(customDefaultFilterChainManager());
		return c;
	}
	
	
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(){
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager());
		return shiroFilterFactoryBean;
	}
}